use Time;
config const numt = here.numCores;
var t: Timer;
var SIZE: real=9999.0;
var THETA_SQUARE: real=0.25;
var SOFTEN: real=18;
var DAMPING: real=0.1;
config const num_iterations: int; 
config const timestep: real; 
config const input: string; 
config const output: string;
proc dclose(x1,y1,x2,y2: real): bool{
	if (((x1-x2)*(x1-x2)+(y1-y2)*(y1-y2))**0.5<0.00000000000000000001){
		return true;
	}else{
		return false;
	}
} 
class body {
        var x:real;
        var y:real;
        var weight:int;
        var vel_x:real;
        var vel_y:real;
        var accln_x:real;
        var accln_y:real;
}
class node {
	var	lock: sync bool;
  	var	st: int;//0:empty 1:leaf 2:node
  	var loc1: int;//loc for st1
  	var children: [0..3] node;
  	var parent: node;
  	var mass: int;
  	var b: body;
  	var x_start,x_end,y_start,y_end: real;
  	var loc_x,loc_y: real;
  	proc init(x1,x2,y1,y2:real){
  		st=0;
  		x_start=x1;
  		x_end=x2;
  		y_start=y1;
  		y_end=y2;
  	}
  	proc print(de:int){
  		if(st==2){
  			for i in {1..de}{
  				write(" ");
  			}
  			writeln("w ",mass);
  			children(0).print(de+1);
  			children(1).print(de+1);
  			children(2).print(de+1);
  			children(3).print(de+1);
  		}else{
  			if(st==1){
  				for i in {1..de}{
  					write(" ");
  				}
  				writeln("w ",mass);
  			}
  		}
  	}
}
//Build tree
proc build_tree(para:node,target:body){
	var xm,ym :real;
	xm=(para.x_start+para.x_end)/2;
	ym=(para.y_start+para.y_end)/2;
	var loc: int = 0;
	var syncb: bool;
	para.lock=true;
	if(target.x>xm){
		loc+=1;
	}
	if(target.y>ym){
		loc+=2;
	}
	if(para.st==0){
		para.st=1;
		para.mass=target.weight;
		para.loc_x=target.x;
		para.loc_y=target.y;
		para.loc1=loc;
		para.b=target;
		syncb=para.lock;
		return;
	}else{
		if(para.st==1){
			if(dclose(para.loc_x,para.loc_y,target.x,target.y)){
				para.loc_x=(para.loc_x*para.mass+target.x*target.weight)/(para.mass+target.weight);
				para.loc_y=(para.loc_y*para.mass+target.y*target.weight)/(para.mass+target.weight);
				para.mass+=target.weight;
				syncb=para.lock;
				return;
			}
			para.st=2;
			for i in {0..3}{
					para.children(i)=new node();
			}
			para.children(0).init(para.x_start,xm,para.y_start,ym);
			para.children(1).init(xm,para.x_end,para.y_start,ym);
			para.children(2).init(para.x_start,xm,ym,para.y_end);
			para.children(3).init(xm,para.x_end,ym,para.y_end);
			para.children(0).parent=para;
			para.children(1).parent=para;
			para.children(2).parent=para;
			para.children(3).parent=para;
			para.loc_x=(para.loc_x*para.mass+target.x*target.weight)/(para.mass+target.weight);
			para.loc_y=(para.loc_y*para.mass+target.y*target.weight)/(para.mass+target.weight);
			para.mass+=target.weight;
			syncb=para.lock;
			build_tree(para.children(para.loc1),para.b);
			build_tree(para.children(loc),target);
			return;
		}else{
			if(dclose(para.loc_x,para.loc_y,target.x,target.y)){
				para.loc_x=(para.loc_x*para.mass+target.x*target.weight)/(para.mass+target.weight);
				para.loc_y=(para.loc_y*para.mass+target.y*target.weight)/(para.mass+target.weight);
				para.mass+=target.weight;
				syncb=para.lock;
				return;
			}
			para.loc_x=(para.loc_x*para.mass+target.x*target.weight)/(para.mass+target.weight);
			para.loc_y=(para.loc_y*para.mass+target.y*target.weight)/(para.mass+target.weight);
			para.mass+=target.weight;
			syncb=para.lock;
			build_tree(para.children(loc),target);
			return;
		}
	}
}
proc cal_acc(para:node,target:body){
	var dist,x,y,mag,ss: real;
	if(para.st==2){
		x=para.loc_x-target.x;
		y=para.loc_y-target.y;
		dist=x*x+y*y;
		ss=para.x_start-para.x_end;
		if(ss*ss<THETA_SQUARE*dist){
			dist+=SOFTEN;
			dist=dist**1.5;
			mag=para.mass/dist;
			target.accln_x += mag*x;
        	target.accln_y += mag*y;
		}else{
			cal_acc(para.children(0),target);
			cal_acc(para.children(1),target);
			cal_acc(para.children(2),target);
			cal_acc(para.children(3),target);
		}
	}else{
		if(para.st==1){
			x=para.loc_x-target.x;
			y=para.loc_y-target.y;
			dist=x*x+y*y;
			dist+=SOFTEN;
			dist=dist**1.5;
			mag=para.mass/dist;
			target.accln_x += mag*x;
        	target.accln_y += mag*y;
		}
	}
}
proc move(target:body){
 	target.vel_x += target.accln_x * timestep; 
    target.vel_y += target.accln_y * timestep;
    target.vel_x *= DAMPING;
    target.vel_y *= DAMPING;
    target.x += target.vel_x * timestep;
    target.y += target.vel_y * timestep;
}
proc remove(para:node){
	if(para.st==2){
		remove(para.children(0));
		remove(para.children(1));
		remove(para.children(2));
		remove(para.children(3));
	}
	delete para;
}
proc r2 (a:real):real{
	var k,j: int;
	var b: real;
	if(a>0){
		k=(a*1000):int;
	}else{
		k=(-a*1000):int;
	}
	j=k%10;
	if(j<5){
		k=k/10;
	}else{
		k=k/10;
		k+=1;
	}
	b=(k:real)/100;
	if(a>0){
		return b;
	}else{
		return -b;
	}
}
//writeln(num_iterations," ",timestep," ",input," ",output);
var inputFile: file=open(input,iomode.r);
var reader=inputFile.reader();
var outputFile: file=open(output,iomode.cw);
var writer=outputFile.writer();
var n: int;
n= reader.read(int);
var table: [0..n-1] body;
var root: node;
for i in {0..n-1}{
	reader.readln();
    table(i)=new body(reader.read(real),reader.read(real),reader.read(int),reader.read(real),reader.read(real),0,0);
}
reader.close();
inputFile.close();
t.start();
for t in {0..num_iterations-1}{
	root =new node();
	root.init(-SIZE,SIZE,-SIZE,SIZE);
	for i in {0..n-1}{
		table(i).accln_x=0;
    	table(i).accln_y=0;
    }
	for i in {0..n-1}{
		build_tree(root,table(i));
	}
	//root.print(0);
	forall i in {0..n-1}{
		cal_acc(root,table(i));
	}
	forall i in {0..n-1}{
		move(table(i));
	}
	remove(root);
}
t.stop();
writeln("Time: ",t.elapsed(), " seconds.");
writer.writeln(n);
for i in {0..n-1}{
	writer.writeln(format("%.2f",table(i).x),format(" %.2f",table(i).y)," ",table(i).weight,format(" %.2f",table(i).vel_x),format(" %.2f",table(i).vel_y));
}
writer.close();
outputFile.close();

